#!/bin/bash -e

FAN_STATUS_UNKNOWN="Unknown"
FAN_STATUS_NORMAL="Normal"
FAN_STATUS_ABNORMAL="Abnormal"
FAN_FAIL_REASON=""

create_log()
{
    local service="xyz.openbmc_project.Logging"
    local object_path="/xyz/openbmc_project/logging"
    local interface="xyz.openbmc_project.Logging.Create"
    local message="Fan status LED asserted"
    local severity="xyz.openbmc_project.Logging.Entry.Level.Error"
    local arg="CALLOUT_INVENTORY_PATH"
    local value="/xyz/openbmc_project/inventory/fan"

    echo "FAN status LED asserted by $FAN_FAIL_REASON"
    busctl call "$service" "$object_path" "$interface" Create "ssa{ss}" "$message" "$severity" 1 "$arg" "$value"
}

resolve_log()
{
    local service="xyz.openbmc_project.ObjectMapper"
    local object_path="/xyz/openbmc_project/inventory/fan/fault"
    local interface="xyz.openbmc_project.Association"
    local property="endpoints"

    mapfile -t -d " " endpoint_array < <(busctl get-property "$service" "$object_path" "$interface" "$property" | tr -d '"\n')

    for ((i = 2; i < ${#endpoint_array[@]}; i++)); do
        endpoint="${endpoint_array[$i]}"
        busctl set-property xyz.openbmc_project.Logging "$endpoint" xyz.openbmc_project.Logging.Entry Resolved b true
    done
}

check_fcb_fan_status()
{
    local fcb_num=$1

    local service="xyz.openbmc_project.FanSensor"
    local interface="xyz.openbmc_project.Sensor.Threshold.Critical"
    local property_list=("CriticalAlarmHigh" "CriticalAlarmLow")
    local in_out=("IL" "OL")

    for index in {0..7}
    do
        local fan_number=$((((fcb_num - 1) * 4) + (index / 2) + 1))
        local io_index=$((index % 2))
        local sensor_name="FCB_${fcb_num}_FAN_${fan_number}_TACH_${in_out[$io_index]}_SPEED_RPM"
        local object_path="/xyz/openbmc_project/sensors/fan_tach/$sensor_name"

        for property in "${property_list[@]}"; do
            tach_alarm=$(busctl get-property "$service" "$object_path" "$interface" "$property" | cut -d ' ' -f2)
            if [ "$tach_alarm" = "true" ]; then
                echo "$FAN_STATUS_ABNORMAL|$sensor_name $property alarm"
                return 0
            fi
        done

        # Check FCB whether is AC off
        local operation_interface="xyz.openbmc_project.State.Decorator.OperationalStatus"
        functional=$(busctl get-property "$service" "$object_path" "$operation_interface" Functional | awk '{print $NF}')
        if [ "$functional" = "false" ]; then
            echo "$FAN_STATUS_ABNORMAL|FCB$fcb_num is not functional. The AC may be off."
            return 0
        fi
    done

    echo "$FAN_STATUS_NORMAL|"
    return 0
}

pre_status=$FAN_STATUS_UNKNOWN

while true
do
    fan_status=$FAN_STATUS_NORMAL
    FAN_FAIL_REASON=""

    # check presence service is active
    presence_active=$(systemctl is-active xyz.openbmc_project.gpiopresence.service)
    if [ "$presence_active" != "active" ]; then
        echo "Presence service is not active"
        continue
    fi
    # check fan sensor service is active
    sensor_active=$(systemctl is-active xyz.openbmc_project.fansensor.service)
    if [ "$sensor_active" != "active" ]; then
        echo "Fan sensor service is not active"
        continue
    fi

    # FCB1 ~ FCB6
    for i in {1..6}
    do
        # Check the presence of each FCB
        presence=$(
            busctl introspect xyz.openbmc_project.gpiopresence \
                /xyz/openbmc_project/GPIODeviceDetected/FanControlBoard"${i}" \
                > /dev/null 2>&1; echo $?
        )

        if [ "$presence" != "0" ]; then
            fan_status=$FAN_STATUS_ABNORMAL
            FAN_FAIL_REASON="FCB$i not present"
            break
        else
            # Check each sensor on the FCB whether alert critical alarm
            result=$(check_fcb_fan_status "$i")
            fan_status=$(echo "$result" | cut -d '|' -f1)
            FAN_FAIL_REASON=$(echo "$result" | cut -d '|' -f2)
            if [ "$fan_status" = "$FAN_STATUS_ABNORMAL" ]; then
                break
            fi
        fi
    done

    if [ "$fan_status" = "$FAN_STATUS_ABNORMAL" ] && [ "$pre_status" != "$FAN_STATUS_ABNORMAL" ]; then
        create_log
        pre_status="$FAN_STATUS_ABNORMAL"
    elif [ "$fan_status" = "$FAN_STATUS_NORMAL" ] && [ "$pre_status" != "$FAN_STATUS_NORMAL" ]; then
        resolve_log
        pre_status="$FAN_STATUS_NORMAL"
    fi
    sleep 1
done
